// Copyright (c) Pomelo Foundation. All rights reserved.
// Licensed under the MIT. See LICENSE in the project root for license information.

using System;
using JetBrains.Annotations;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Infrastructure.Internal;
using Microsoft.EntityFrameworkCore.Internal;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Metadata.Conventions;
using Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal;
using Microsoft.EntityFrameworkCore.ChangeTracking.Internal;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Migrations.Internal;
using Microsoft.EntityFrameworkCore.Query.ExpressionTranslators.Internal;
using Microsoft.EntityFrameworkCore.Query.Internal;
using Microsoft.EntityFrameworkCore.Query.Sql.Internal;
using Microsoft.EntityFrameworkCore.Storage;
using Microsoft.EntityFrameworkCore.Storage.Internal;
using Microsoft.EntityFrameworkCore.Update.Internal;
using Microsoft.EntityFrameworkCore.Utilities;
using Microsoft.EntityFrameworkCore.ValueGeneration.Internal;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Pomelo.EntityFrameworkCore.MyCat.ValueGeneration.Internal;
using Microsoft.EntityFrameworkCore.Update;
using Microsoft.EntityFrameworkCore.ValueGeneration;
using Microsoft.EntityFrameworkCore.Query.ExpressionTranslators;
using Microsoft.EntityFrameworkCore.Query.Sql;

// ReSharper disable once CheckNamespace

namespace Microsoft.Extensions.DependencyInjection
{
    public static class MyCatEntityFrameworkServicesBuilderExtensions
    {
        public static IServiceCollection AddEntityFrameworkMyCat([NotNull] this IServiceCollection serviceCollection)
        {
            Check.NotNull(serviceCollection, nameof(serviceCollection));
            var services = new EntityFrameworkRelationalServicesBuilder(serviceCollection);
            services.TryAdd<IDatabaseProvider, DatabaseProvider<MyCatOptionsExtension>>()
              .TryAdd<IRelationalConnection>(p => p.GetService<MyCatRelationalConnection>())
              .TryAdd<IBatchExecutor>(p => p.GetService<MyCatBatchExecutor>())
              .TryAdd<IDatabaseCreator>(p => p.GetService<MyCatDatabaseCreator>())
              .TryAdd<ISqlGenerationHelper>(p => p.GetService<MyCatSqlGenerationHelper>())
              .TryAdd<IRelationalDatabaseCreator>(p => p.GetService<MyCatDatabaseCreator>())
              .TryAdd<IMigrationsAnnotationProvider>(p => p.GetService<MyCatMigrationsAnnotationProvider>())
              .TryAdd<IHistoryRepository>(p => p.GetService<MyCatHistoryRepository>())
              .TryAdd<IMigrationsSqlGenerator>(p => p.GetService<MyCatMigrationsSqlGenerator>())
              .TryAdd<IModelSource>(p => p.GetService<MyCatModelSource>())
              .TryAdd<IUpdateSqlGenerator>(p => p.GetService<MyCatUpdateSqlGenerator>())
              .TryAdd<IMigrationsAnnotationProvider>(p => p.GetService<MyCatMigrationsAnnotationProvider>())
              .TryAdd<IValueGeneratorCache>(p => p.GetService<MycatValueGeneratorCache>())
              .TryAdd<IRelationalTypeMapper>(p => p.GetService<MyCatTypeMapper>())
              .TryAdd<IConventionSetBuilder>(p => p.GetService<MyCatConventionSetBuilder>())
              .TryAdd<IModificationCommandBatchFactory>(p => p.GetService<MyCatModificationCommandBatchFactory>())
              .TryAdd<IRelationalValueBufferFactoryFactory>(p => p.GetService<TypedRelationalValueBufferFactoryFactory>())
              .TryAdd<ICompositeMethodCallTranslator>(p => p.GetService<MyCatCompositeMethodCallTranslator>())
              .TryAdd<IMemberTranslator>(p => p.GetService<MyCatCompositeMemberTranslator>())
              .TryAdd<IQuerySqlGeneratorFactory>(p => p.GetService<MyCatQuerySqlGenerationHelperFactory>())
              .TryAdd<IValueGeneratorSelector>(p => p.GetService<MyCatValueGeneratorSelector>());

              services.TryAdd(new ServiceCollection()

                .AddSingleton<MycatValueGeneratorCache>()
                .AddSingleton<MyCatTypeMapper>()
                .AddSingleton<MyCatSqlGenerationHelper>()
                .AddSingleton<MyCatModelSource>()
                .AddSingleton<MyCatAnnotationProvider>()
                .AddSingleton<MyCatMigrationsAnnotationProvider>()
                .AddScoped<MyCatBatchExecutor>()
                .AddScoped<MyCatConventionSetBuilder>()
                .AddScoped<TableNameFromDbSetConvention>()
                .AddScoped<MyCatUpdateSqlGenerator>()
                .AddScoped<MyCatModificationCommandBatchFactory>()
                .AddScoped<MyCatValueGeneratorSelector>()
                .AddScoped<MyCatRelationalConnection>()
                .AddScoped<MyCatDatabaseCreator>()
                .AddScoped<MyCatHistoryRepository>()
                .AddScoped<MyCatSchemaGenerator>()
                .AddScoped<MyCatMigrationsSqlGenerator>()
                .AddScoped<MyCatModificationCommandBatchFactory>()
                .AddScoped<IChangeDetector, MyCatChangeDetector>()
                .AddScoped<IPropertyListener, IChangeDetector>(p => p.GetService<IChangeDetector>())
                .AddScoped<MyCatMigrationsModelDiffer>()
                .AddScoped<IMigrationsModelDiffer, MyCatMigrationsModelDiffer>()
                .AddScoped<IMigrator, MyCatMigrator>().AddQuery());


                services.TryAddCoreServices();
            return serviceCollection;
        }

        private static IServiceCollection AddQuery(this IServiceCollection serviceCollection)
        {
            return serviceCollection
                .AddScoped<MyCatQueryCompilationContextFactory>()
                .AddScoped<MyCatCompositeMemberTranslator>()
                .AddScoped<MyCatCompositeMethodCallTranslator>()
                .AddScoped<MyCatQuerySqlGenerationHelperFactory>();
        }
    }
}
